//fread(*ptr,size,num,File *f)    
#include<netinet/in.h>  // sockaddr_in
#include<sys/types.h>   // socket
#include<sys/socket.h>  // socket
#include<stdio.h>       // printf
#include<stdlib.h>      // exit
#include<string.h>      // bzero
#include<unistd.h>
#include<arpa/inet.h>
#include<fstream>
#define SERVER_PORT 8000
#define LENGTH_OF_LISTEN_QUEUE 10
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
#include <NTL/ZZ.h>                 
#include <NTL/BasicThreadPool.h>
#include <NTL/lzz_pXFactoring.h>
#include "FHE.h"                    
#include "timing.h"                 
#include "EncryptedArray.h"          
#include <cassert>                   
#include <cstdio>                   
#include <iostream>
#include <math.h> 
using namespace std;
int xiabiao[BUFFER_SIZE];

struct Element
{
    double data;
    Ctxt data2;                                  
    char sign;
    char bracket_left;
    char bracket_right;
    Element *next;
};
Ctxt FHE_Enc(long num, const FHEPubKey& publicKey)
{
    Ctxt Enc(publicKey);
    Vec<ZZ> v;
    v.SetLength(2);
    v[0] = num;
    v[1] = 1;
    publicKey.Encrypt(Enc, to_ZZX(v));
    return Enc;
}

long FHE_Dec(Ctxt ctxt, long p, const FHESecKey& secretKey)
{
    long Dec;
    ZZX ptxt;
    secretKey.Decrypt(ptxt, ctxt);
    conv(Dec, ptxt[0]);
    if (Dec > p/2)
        Dec -= p;
    return Dec;
}





Ctxt FHE_Add(Ctxt Ea, Ctxt Eb)
{
    Ctxt ctSum = Ea;
    ctSum += Eb;
    return ctSum;
}



Ctxt FHE_Mul(Ctxt Ea, Ctxt Eb, long p, const FHESecKey& secretKey)
{
    // if a or b is 0, return E[0].
    if (FHE_Dec(Ea, p, secretKey) == 0)
        return Ea;
    else if (FHE_Dec(Eb, p, secretKey) == 0)
        return Eb;
    else
    {
        Ctxt ctMul = Ea;
        ctMul *= Eb;
        return ctMul;
    }
}

Ctxt FHE_Sub(Ctxt Ea, Ctxt Eb, const FHEPubKey& publicKey)
{
    // sub = b*(-1)+a
    Ctxt minus1 = FHE_Enc(-1, publicKey);
    Ctxt ctSub = Eb;
    ctSub *= minus1;
    ctSub += Ea;
    return ctSub;
}



Ctxt FHE_Div(Ctxt Ea, Ctxt Eb, long p,
            const FHEPubKey& publicKey, const FHESecKey& secretKey)
{
    
    long quotient = 0;  
    ZZX ptMul, ptMul2, ptSub, ptSum, ptEa, ptEb;
    
    bool positive = true;
    long EaDec = FHE_Dec(Ea, p, secretKey);
    if (EaDec < 0) positive = false;
    long EbDec = FHE_Dec(Eb, p, secretKey);
    if (EbDec == 0) 
    {
        cout << "Error: Invalid Denominator." << endl;
        Ctxt ctDiv = FHE_Enc(0, publicKey);
        return ctDiv;
    }
    else if(EaDec == 0) 
        return Ea;
    else
    {
        long MulDec = FHE_Dec(FHE_Mul(Ea, Eb, p, secretKey), p, secretKey);    
        if(MulDec >= 0)
        {
            while (1)
            {
                Ctxt ctSub = FHE_Sub(Ea, Eb, publicKey);
                long sub = FHE_Dec(ctSub, p, secretKey);
                if (sub >= 0 && positive || sub <= 0 && !positive)
                {
                    Ea = ctSub;
                    quotient ++;
                }
                else break;
            }
        }
        
        else 
        {
            while (1)
            {
                Ctxt ctSum = FHE_Add(Ea, Eb);
                long temp = FHE_Dec(FHE_Mul(ctSum, Ea, p, secretKey), p, secretKey);
                if (temp >= 0)
                {
                    Ea = ctSum;
                    quotient --;
                }
                else break;            
            }
        }
        Ctxt ctDiv = FHE_Enc(quotient, publicKey);
        return ctDiv;
    }
    
}
//---------------------------------------------------------------------------------------------------------------
int check(char *s)
{
    int count_bracket=0;
    int i=0;
    while(i<strlen(s))
    {
        if(s[i]=='(') count_bracket++;
        else if(s[i]==')') count_bracket--;
        if(count_bracket<0)
            return 0;
        if(!(s[i]>='0'&&s[i]<='9'||s[i]==')'||s[i]=='('||s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/'))
            return 0;
        i++;
    }
    if(count_bracket) return 0;
    return 1;
}


void create_exqression(char *s,Element *head,Ctxt* value[],const FHEPubKey& publicKey)
{
    Element *q=head;
    int varofnum=0;
    q->next=(Element *)malloc(sizeof(Element));
    q=q->next,q->next=NULL;                        
    q->bracket_left=q->bracket_right='\0';                      //括号            
    q->sign='\0',q->data=0;
    int x=0;
    while(x<strlen(s))
    {
        /*if(s[x]>='0'&&s[x]<='9')                     //
        {
            while(s[x]>='0'&&s[x]<='9'&&s[x]!='\0')
             q->data*=10,q->data+=s[x++]-'0';
            x--;
        }*/
        if((s[x]>='a'&&s[x]<='z')||(s[x]>='A'&&s[x]<='Z'))   //s是表达式字符串             
		{
			varofnum+=1;
			q->data2=*value[varofnum];           //把value数组里面的数组放到节点

			q->data=varofnum*1.0; 
		} 
        else if(s[x]=='+'||s[x]=='-'||s[x]=='*'||s[x]=='/')
        {
            q->next=(Element *)malloc(sizeof(Element));
            if(!q->next)
            {
                cout<<"ERROR"<<endl;
                exit(0);
            }
            q=q->next,q->next=NULL;
            q->bracket_left=q->bracket_right='\0';
            q->sign=s[x],q->data=0;
        }
        else if(s[x]==')')
        {
            q->bracket_right=')';
            q->bracket_left='\0';
        }
        else if(s[x]=='(')
        {
            q->bracket_left='(';
            q->bracket_right='\0';
        }
        x++;
    }
    q=head->next;
    while(q->next) 
	q=q->next;
    q->next=(Element *)malloc(sizeof(Element));
    q=q->next;
    q->data=0,q->sign='+',q->next=NULL;
    q->data2=FHE_Enc(0, publicKey);
    q->bracket_left=q->bracket_right='\0';
}

Ctxt calculate(Element *start,Element *end,long p, const FHEPubKey& publicKey,const FHESecKey& secretKey)     //链表中存放的是操作数
{
     Ctxt a(publicKey),b(publicKey);                                    //？？？？？？？？
    Element *q=start;
    while(q!=end)
    {
        if(q->next->sign=='*')
        {
            Ctxt Ea=q->data2;
            Ctxt Eb=q->next->data2;
            /*Ctxt Ea = FHE_Enc(a, publicKey);
            Ctxt Eb = FHE_Enc(b, publicKey);*/
            
            Ctxt mul = FHE_Mul(Ea, Eb, p, secretKey);
        	//q->data=FHE_Dec(mul, p, secretKey);
        	q->data2=mul;
        	
            q->next=q->next->next;
            q=start;
			continue;
        }
        else if(q->next->sign=='/')
        {
            /*a=q->data;
            b=q->next->data;*/
            Ctxt Ea=q->data2;
            Ctxt Eb=q->next->data2;
            /*Ctxt Ea = FHE_Enc(a, publicKey);
            Ctxt Eb = FHE_Enc(b, publicKey);*/
            Ctxt div = FHE_Div(Ea, Eb, p, publicKey, secretKey);
            //q->data=FHE_Dec(div, p, secretKey);
            q->data2=div;
            q->next=q->next->next;
            q=start;continue;
        }
        q=q->next;
    }
    //double sum=start->data;
    Ctxt sum=start->data2;
    start=start->next;
    while(start!=end)
    {
        if(start->sign=='+') 
        {
            a=sum;
            b=start->data2;
            /*Ctxt Ea = FHE_Enc(a, publicKey);
           	Ctxt Eb = FHE_Enc(b, publicKey);
            Ctxt su = FHE_Add(Ea, Eb);*/
            Ctxt su=FHE_Add(a,b); 
            //sum=FHE_Dec(su, p, secretKey);
            sum=su;
        }
        else 
        {
            a=sum;
            b=start->data2;
            /*Ctxt Ea = FHE_Enc(a, publicKey);
           	Ctxt Eb = FHE_Enc(b, publicKey);
            Ctxt sub = FHE_Sub(Ea, Eb, publicKey);*/
            //sum=FHE_Dec(sub, p, secretKey);
            Ctxt sub=FHE_Sub(a,b,publicKey);
        }
        start=start->next;                                       //？？？？上面为啥没有
    }
    return sum;
}
void cancel_bracket(Element *head,long p,const FHEPubKey& publicKey,const FHESecKey& secretKey)
{
    Element *start=head->next;
    Element *q=head;
    while(start)
    {
        int flag=0;
        if(start->bracket_left)
        {
            Element *end=start;
            int count_bracket=1;
            while(end)
            {
                if(end->bracket_right)
                {
                    count_bracket--;
                    if(!count_bracket)
                    {
                        start->data2=calculate(start,end->next,p,publicKey,secretKey);
                        start->bracket_left=start->bracket_right='\0';
                        start->next=end->next;
                    }
                }
                else if(end->bracket_left)
                {
                    flag=1;
                    count_bracket=1;
                    start=end;
                }
                end=end->next;
            }
        }
        if(flag) start=q;
        start=start->next;
    }
}


Element* cal_result(char *buf,Ctxt* value[],const FHEPubKey& publicKey)
{
	Element *head=(Element *)malloc(sizeof(Element));
	head->next=NULL;
	create_exqression(buf,head,value,publicKey);
	return head;
} 

/*getstratandend(char *buf1)
{
	flag="#";  
 	position=0;  
 	int i=0;  
 	while((position=buf1.find_first_of(flag,position))!=string::npos)  
 	{  
  	 //position=s.find_first_of(flag,position);  
 	 //cout<<"position  "<<i<<" : "<<position<<endl;  //\BB\F1ȡ#\D7\D6\CF±\EA\B7ָ\EE\D3\C3 
	 xiabiao[i]=position;  
 	 position++;  
 	 i++;  
 	}
}*/
//---------------------------------------------------------------------------------------------------------------
int main(void)
{
	Element *head,*end;
    
    long m = 0;          
    long p = 2147483647; 
    long r = 1;
    long L = 16;
    long c = 3;
    long w = 64;
    long d = 0;
    long k = 128;
    long s = 0;
    m = FindM(k, L, c, p, d, s, 0);

    
    FHEcontext context(m, p, r);
    buildModChain(context, L, c);
    ZZX G = context.alMod.getFactorsOverZZ()[0];
    
    
    FHESecKey secretKey(context);
    const FHEPubKey& publickey = secretKey;
    secretKey.GenSecKey(w);
    FHEPubKey& publicKey=secretKey;
	//-------------------------------------------
   
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);
    server_addr.sin_port = htons(SERVER_PORT);
    int server_socket_fd = socket(PF_INET, SOCK_STREAM, 0);
    if(server_socket_fd < 0)
    {
        perror("Create Socket Failed:");
        exit(1);
    }
    int opt = 1;
    setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

   
    if(-1 == (bind(server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))))
    {
        perror("Server Bind Failed:");
        exit(1);
    }
    if(-1 == (listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE)))
    {
        perror("Server Listen Failed:");
        exit(1);
    }

	
    while(1)
    {
       
        struct sockaddr_in client_addr;
        socklen_t client_addr_length = sizeof(client_addr);

        int new_server_socket_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length);
        if(new_server_socket_fd < 0)
        {
            perror("Server Accept Failed:");
            break;
        }
//-------------------------------------------------------------
		char buf[BUFFER_SIZE];                //a+a+a
		char buffer[BUFFER_SIZE];
                char buffer1[BUFFER_SIZE];                //temp
                char buffer2[BUFFER_SIZE][BUFFER_SIZE];  //temepropory
		char buffer3[BUFFER_SIZE];
		char temp[10];                           //#
		Ctxt* value[BUFFER_SIZE];               //cypher
	    int i=0;
		int ncount[2];                       //geshu

		//Ctxt ans;                          //result Ctxt ans(publicKey);     
        //Ctxt* e;  


		if(recv(new_server_socket_fd, buf, BUFFER_SIZE, 0)<0)    //a+a+a
        {
            perror("Server Recieve Data Failed:");
            break;
        }
		if(recv(new_server_socket_fd, ncount, BUFFER_SIZE, 0)<0)    
        {
            perror("Server Recieve Data Failed:");
            break;
        }
	
 //------------------------------------------------------------------ 
        char file_name[]="cypher.txt";     
	    FILE *fp1= fopen(file_name,"wb");
	   
        if(NULL == fp1)
        {
            printf("File:%s Not Found\n", file_name);
        }
        else
        {
            int length = 0;
            while(length = recv(new_server_socket_fd, buffer, BUFFER_SIZE, 0)> 0)
            {  
              //printf("%d\n",length);
              //printf("%s\n",buffer);          
	          length=strlen(buffer);
              if(fwrite(buffer, sizeof(char), length, fp1) < length)
              {
                 printf("File:\t%s Write Failed\n", file_name);
                 break;
             }
        	bzero(buffer, BUFFER_SIZE);
			}
		}
   
      //printf("Receive File:\t%s From Server IP Successful!\n", file_name);
    fclose(fp1);
//------------------------------------------------------------------------------
    int length;
    while((length = fread(buffer1, sizeof(char), 100, fp1)) > 0)
    {
         for(int j=0;j<strlen(buffer1);j++)
                {
	 
                if(buffer1[j]=='#')
                i++;
                else
                {
                temp[0]=buffer1[j];
                strcat(buffer2[i],temp);
                }
                }
            }
//----------------------------------------------------------------------------------
		    for(int i=0;i<ncount[0];i++)                                //
			{
		       fstream keyfile("tempcyper.txt",fstream::out|fstream::trunc);
			   keyfile<<buffer2[i];
			   keyfile.close();
			   fstream key("tempcyper.txt",fstream::in);
			   //value[i]=new Ctxt(publicKey);
			   key>>*value[i];                          
    		   key.close();
			}
 //-----------------------------------------------------------------------------------------------
	        head=cal_result(buf,value,publicKey);                              
    	    end=head->next;
    	    while(end->next)
			{
    		end=end->next;
			}
			Ctxt ans(publicKey);
    	    ans=calculate(head->next,end,p,publicKey ,secretKey);                              
	        fstream keyfi("serverans.txt",fstream::out|fstream::trunc);                     //result
	        //e=&ans;
		    keyfi<<ans;                                            
		    keyfi.close();
            delete value[];
//send--------------------------------------------------------------------------------------------
		
        FILE *fp2 = fopen("serverans.txt", "rb");
        if(NULL == fp2)
        {
            printf("File:%s Not Found\n", file_name);
        }
        else
        {
            bzero(buffer, BUFFER_SIZE);
            int length = 0;
            while((length = fread(buffer3, sizeof(char), BUFFER_SIZE, fp2)) > 0)
            {
                if(send(new_server_socket_fd, buffer, length, 0) < 0)
                {
                    printf("Send File:%s Failed./n", file_name);
                    break;
                }
                bzero(buffer, BUFFER_SIZE);
            }
            fclose(fp2);
            printf("File:%s Transfer Successful!\n", file_name);
        }
//----------------------------------------------------
		
	    close(new_server_socket_fd);
        close(server_socket_fd);}
        return 0;
}
//-----------------------------------------------------------------------------------------------
  /* if(recv(new_server_socket_fd, buffer, BUFFER_SIZE, 0) < 0)    //filename
        {
            perror("Server Recieve Data Failed:");
            break;
        }*/

        /*char file_name[FILE_NAME_MAX_SIZE+1];
	     printf("enter");
        scanf("%s",file_name);
        bzero(file_name, FILE_NAME_MAX_SIZE+1);
        strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
        //printf("%s\n", file_name);*/


		 //bzero(buffer2, BUFFER_SIZE);
            //puts(buffer2[i]);
            //printf("buffer2[0]:%s\n",buffer2[0]);
            //printf("buffer2[1]:%s\n",buffer2[1]);
            //printf("buffer2[2]:%s\n",buffer2[2]);
            //puts(buffer3);
            // 关闭文件
            
            //printf("File:%s Transfer Successful!\n", buffer);


			
		   /*
		    fstream keyf("serverans.txt",fstream::out|fstream::trunc);
		   keyf><<uf1;                                             
		   keyf.close();
		   
			 
			   
				 
				   if(send(client_sockfd,buf1,strlen(buf1),0)<0)              
		   {
			cout<<"send ans error";
			return 1;
		   } */
